package co.za.alacrity.factorypattern;

import java.util.Random;

import co.za.alicrity.exactcover.ExactCoverMatrix;
import co.za.alicrity.exactcover.ExactCoverSparceMatrix;
import co.za.alicrity.exactcover.SolutionList;
import co.za.alicrity.exactcover.TreeNodes;

public class DancingLinks implements ProblemSolver{
	
	private Random rand = new Random();
	public static final int REMOVE_CELL_COUNT=50;

	@Override
	public boolean solve(ExactCoverMatrix exactCoverMatrix) {
		
		ExactCoverSparceMatrix em = new ExactCoverSparceMatrix(exactCoverMatrix);
		
		SolutionList solutions = new SolutionList(exactCoverMatrix);
		
		TreeNodes topNode = new TreeNodes(em, solutions);
		
		if (!solutions.hasSolution()) return false;
		
		solutions.applySolution(0);
		return true;
		
		
		
		
	}

	@Override
	public int[][] genarator() {
		
		
		int[][] arrayGrid = new int[9][];
		
		for(int r = 0;r<9;r++){
			arrayGrid[r] = new int[9];
			for(int col = 0;col<9;col++){
				 int value = ((r/3)+1)+((r%3)*3);
				 arrayGrid[r][col]=((col+value)%9)==0?9:((col+value)%9);
				
			}
			
			
		}
		
		for (int numSwops=0;numSwops<1000;numSwops++){
			int type = rand.nextInt(4);
			switch (type) {
			case 0 : arrayGrid = swopColumns(arrayGrid); break;
			case 1 : arrayGrid = swopRows(arrayGrid); break;
			case 2 : arrayGrid = swopBigBlock(arrayGrid); break;
			case 3 : arrayGrid = swopBigBlockColumn(arrayGrid); break;
			}
		}
		
		for (int r=0;r<REMOVE_CELL_COUNT;r++){
			arrayGrid = removeCell(arrayGrid);
		}
			
		
		//System.out.println(toString(arrayGrid));
		return arrayGrid;
	}
	
	private int[][] removeCell(int[][] grid) {
		int r = rand.nextInt(9);
		int c = rand.nextInt(9);
		
		if (grid[r][c]==0){
			return removeCell(grid);
		}
		grid[r][c]=0;
		return grid;
	}

	public int[][] swopColumns(int[][] grid){
		int column1 = rand.nextInt(9);
		int column2 = 0;
		if (column1%3==0){
			column2=column1+rand.nextInt(2)+1;
		}
		if (column1%3==1){
			column2=column1+(rand.nextInt(2)==1?1:-1);
		}
		if (column1%3==2){
			column2=column1-(rand.nextInt(2)+1);
		}
		for (int r=0;r<9;r++){
			int temp = grid[r][column1];
			grid[r][column1]=grid[r][column2];
			grid[r][column2]=temp;
		}
		
		return grid;
	}
	public int [][] swopRows(int [][] grid){
		int row1 = rand.nextInt(9);
		int row2 = 0;
		if (row1%3==0){
			row2=row1+rand.nextInt(2)+1;
		}
		if (row1%3==1){
			row2=row1+(rand.nextInt(2)==1?1:-1);
		}
		if (row1%3==2){
			row2=row1-(rand.nextInt(2)+1);
		}
		for (int r=0;r<9;r++){
			int temp = grid[r][row1];
			grid[r][row1]=grid[r][row2];
			grid[r][row2]=temp;
		}
		
		return grid;
	} 
	
	public int [][] swopBigBlock(int [][] grid){
	  int block1 = rand.nextInt(3);
	  int block2 = rand.nextInt(3);
	  for(int r = 0; r<9; r++ ){
		  for(int z = 0 ; z < 3; z++){
			  int temp = grid[r][(block1*3)+z];
			  grid[r][(block1*3)+z]=grid[r][(block2*3)+z];
			  grid[r][(block2*3)+z]=temp;
		  }
	  }
		return grid;
	}
	
	public int [][] swopBigBlockColumn(int [][] grid){
		  int block1 = rand.nextInt(3);
		  int block2 = rand.nextInt(3);
		  for(int r = 0; r<9; r++ ){
			  for(int z = 0 ; z < 3; z++){
				  int temp = grid[(block1*3)+z][r];
				  grid[(block1*3)+z][r]=grid[(block2*3)+z][r];
				  grid[(block2*3)+z][r]=temp;
			  }
		  }
			return grid;
		}
	
	public String toString(int[][] grid){
		String n="";
		for (int r=0;r<13;r++){
			n+="#";
		}
		n+="\n";
		
		
		for (int r=0;r<3;r++){
			n+="#";
			for (int k=0;k<9;k++){
				n+=grid[r][k];
				if ((k+1)%3==0) n+="#";
			}
			n+="\n";
		}
		
		
		for (int r=0;r<13;r++){
			n+="#";
		}
		n+="\n";
		
		
		
		for (int r=3;r<6;r++){
			n+="#";
			for (int k=0;k<9;k++){
				n+=grid[r][k];
				if ((k+1)%3==0) n+="#";
			}
			n+="\n";
		}
		
		
		
		for (int r=0;r<13;r++){
			n+="#";
		}
		n+="\n";
		
		
		
		
		for (int r=6;r<9;r++){
			n+="#";
			for (int k=0;k<9;k++){
				n+=grid[r][k];
				if ((k+1)%3==0) n+="#";
			}
			n+="\n";
		}
		
		for (int r=0;r<13;r++){
			n+="#";
		}
		
		
		return n;
		
	}
	
	public static void main(String args[]){
		new DancingLinks().genarator();
	}

}
